package nwsimplex.graph;

import java.util.Iterator;

/**
 * An Iterator which traverses all Edges within a cycle if two branches of this
 * tree are connected by an imaginary edge between two specified nodes.
 */
public class CycleIterator implements Iterator<Edge> {

    /**
     * The branch used by the CycleIterator
     */
    public enum Branch {

        LEFT, 
        RIGHT, 
        UNDEFINED
    }
    
    private Branch currBranch = Branch.UNDEFINED;
    private Edge current;
    private Vertex left;
    private Vertex right;

    /**
     * Note that the orientation of this cycle is in direction left to right of
     * the imaginary edge.
     *
     * @param left
     * @param right
     */
    public CycleIterator(Vertex left, Vertex right) {
        this.left = left;
        this.right = right;
    }

    /**
     * Gets the branch of the last returned edge, which may be either an element
     * of the left direction or the right direction.
     *
     * @return the direction of the last returned edge or undefined if no
     * traversion step was performed.
     */
    public Branch getCurrentBranch() {
        return currBranch;
    }

    /**
     * Determines if the last returned edge is inorientation of this cycle.
     *
     * @return true if the edge is in direction left to right, false otherwise
     * @throw IllegalStateException if no iteration was performed
     */
    public boolean isInOrientation() {
        switch (currBranch) {
            case LEFT:
                return current.isDownwardPointing();
            case RIGHT:
                return current.isUpwardPointing();
            case UNDEFINED:
            default:
                throw new IllegalStateException();
        }
    }

    /**
     * Gets the cycleroot if the end of the traversion is reached.
     *
     * @return the cycle root or null if there exists a next element.
     */
    public Vertex getCycleRoot() {
        return hasNext() ? null : left;
    }

    @Override
    public boolean hasNext() {
        return left != right;
    }

    @Override
    public Edge next() {
        if (left.depth >= right.depth) {
            current = left.treeEdge;
            left = left.parent;
            currBranch = Branch.LEFT;
        } else {
            current = right.treeEdge;
            right = right.parent;
            currBranch = Branch.RIGHT;
        }

        return current;
    }

    /*
     * Not supported.
     */
    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not supported.");
    }
}